export default {
	name: 'UploadDialog',
	props: {
		modelValue: Boolean,
		currentPath: String
	},
	emits: ['update:modelValue', 'success'],
	setup(props, {emit}) {
		const showDialog = ref(false)
		const selectedFile = ref(null)
		const uploadId = ref('')
		const chunkSize = ref(5 * 1024 * 1024) // 默认分片大小5MB
		const totalChunks = ref(0)
		const progress = ref(0)
		const uploading = ref(false)
		const errorMessage = ref('')
		const uploadedChunks = ref(new Set())
		const concurrency = 3 // 并发上传数
		const fileInput = ref(null);

		// 同步对话框显示状态
		watch(() => props.modelValue, (val) => {
			showDialog.value = val
			if (!val) resetState()
		})
        
        // 重置状态
		const resetState = () => {
			selectedFile.value = null
			uploadId.value = ''
			progress.value = 0
			uploading.value = false
			errorMessage.value = ''
			uploadedChunks.value = new Set();
			if (fileInput.value) {
                fileInput.value.value = '';
            }
		}

		const handleFileChange = (e) => {
            const file = e.target.files?.[0];
            // 每次选择文件时强制重置上传状态
            uploadId.value = '';
            progress.value = 0;
            uploadedChunks.value = new Set();
            totalChunks.value = 0;
            if (!file) return;
            // 黑名单列表（需与后端保持同步）
            const bannedExtensions = [
                'exe', 'dll', 'bat', 'cmd', 
                'js', 'jse', 'vbs', 'wsf',
                'ps1', 'sh', 'iso', 'img',
                'msi', 'psd', 'hta', 'scr',
                'lnk', 'url', 'php', 'py',
                'pl', 'jar', 'class'
            ]
            // 获取文件扩展名（兼容多后缀情况）
            const fileNameParts = file.name.toLowerCase().split('.');
            const ext = fileNameParts.length > 1 ? fileNameParts.pop() : '';
            // 黑名单校验
            if (bannedExtensions.includes(ext)) {
                errorMessage.value = `禁止上传危险文件类型: .${ext}`;
                selectedFile.value = null;
                if (fileInput.value) fileInput.value.value = ''; // 清空文件选择（可选）
                return
            }
            selectedFile.value = file
            errorMessage.value = ''
		}

		const startUpload = async () => {
			if (!selectedFile.value) return
			try {
				uploading.value = true;
				errorMessage.value = '';
				// 初始化前清空已上传分片
                uploadedChunks.value.clear();
                progress.value = 0;
				// 1. 初始化上传
				const res = await axios.post('/v1/upload/start', {
					fileName: selectedFile.value.name,
					totalSize: selectedFile.value.size,
					path: props.currentPath
				}).catch(err => {
					throw new Error(`初始化失败: ${err.response?.data?.message || err.message}`)
				})
				// 强化响应校验
				if (!res.data || res.data.code !== 200) {
					throw new Error(res.data?.message || '初始化返回数据异常')
				}
				const data = res.data.data
				if (!data?.uploadId) {
					throw new Error('缺少必要上传参数')
				}
				uploadId.value = data.uploadId
				chunkSize.value = data.chunkSize || 5 * 1024 * 1024
				totalChunks.value = Math.ceil(selectedFile.value.size / chunkSize.value)
				// 2. 分片上传（增加重试机制）
				await uploadChunks()
				// 3. 完成上传（强化结果校验）
				const completeRes = await axios.post('/v1/upload/complete', null, {
					params: {
						uploadId: uploadId.value
					}
				}).catch(async err => {
                    const isValidationError = err.response?.data?.message?.includes("文件类型")
                    await axios.post('/v1/upload/abort', { uploadId: uploadId.value })  // 失败时尝试清理临时文件
                    // 抛出带类型标识的错误
                    throw { 
                        message: `合并失败: ${err.response?.data?.message || err.message}`,
                        isValidationError
                    }
				})
				if (completeRes.data?.code !== 200) {
					throw new Error(completeRes.data?.message || '文件合并异常')
				}
				const fileUrl = {data: window.APP_CONFIG.baseurl + 'uploads/' + completeRes.data.data.path};
				emit('success', fileUrl);
				emit('update:modelValue', false)
			} catch (error) {
                const errMsg = error.message || '上传失败';
                const isValidationError = error.isValidationError;
                errorMessage.value = errMsg;
                console.error('[Upload Error]', error)
                // 仅网络错误允许重试
                if (!isValidationError && uploadedChunks.value.size > 0) {
                    if (confirm('网络不稳定上传中断，是否继续上传？')) await uploadChunks();
                } else {
                    // 校验失败时强制重置状态
                    uploadId.value = '';
                    selectedFile.value = null;
                }
			} finally {
				uploading.value = false;
			}
		}

		// 分片上传
		const uploadChunks = async (retry = 3) => {
			const chunks = Array.from({length: totalChunks.value}, (_, i) => i);
			const file = selectedFile.value
			try {
				while (uploadedChunks.value.size < totalChunks.value) {
					const pendingChunks = chunks.filter(i => !uploadedChunks.value.has(i)).slice(0, concurrency)
					const results = await Promise.allSettled(
						pendingChunks.map(chunkIndex =>
							uploadSingleChunk(chunkIndex, retry)
						)
					)
					// 处理失败分片
					results.forEach((result, index) => {
						if (result.status === 'rejected') {
							errorMessage.value =`分片 ${pendingChunks[index]+1} 上传失败: ${result.reason.message}`
							throw result.reason
						}
					})
				}
			} catch (error) {
				if (retry > 0) {
					console.warn(`剩余重试次数: ${retry}`)
					return uploadChunks(retry - 1)
				}
				throw error
			}
		}

		// 单分片上传（带重试）
		const uploadSingleChunk = async (chunkIndex, retry) => {
			try {
				const start = chunkIndex * chunkSize.value
				const end = Math.min(selectedFile.value.size, start + chunkSize.value)
				const chunk = selectedFile.value.slice(start, end)
				const formData = new FormData()
				formData.append('uploadId', uploadId.value)
				formData.append('chunkIndex', chunkIndex)
				formData.append('chunk', chunk, selectedFile.value.name)
				const res = await axios.post('/v1/upload/chunk', formData, {
					headers: {
						'Content-Type': 'multipart/form-data'
					}
				})
				if (res.data?.code !== 200) {
					throw new Error(res.data?.message || '分片上传异常')
				}
				uploadedChunks.value.add(chunkIndex)
				progress.value = Math.min(Math.round((uploadedChunks.value.size / totalChunks.value) * 100),100);
			} catch (error) {
				if (retry > 0) {
					return uploadSingleChunk(chunkIndex, retry - 1)
				}
				throw new Error(`分片 ${chunkIndex + 1} 上传失败: ${error.message}`)
			}
		}

		const formatFileSize = (size) => {
			if (!size) return '0 B'
			const units = ['B', 'KB', 'MB', 'GB']
			let i = 0
			while (size >= 1024 && i < 3) {
				size /= 1024
				i++
			}
			return `${size.toFixed(1)} ${units[i]}`
		}

		return {
			showDialog,
			selectedFile,
			progress,
			uploading,
			errorMessage,
			handleFileChange,
			startUpload,
			formatFileSize,
			uploadChunks,
			uploadSingleChunk,
			fileInput
		}
	},

    template: `
	<el-dialog v-model="showDialog" title="分片上传" width="500px" :style="{ '--icon-color': '#409eff' }" @close="$emit('update:modelValue', false)">
		<div style="padding: 20px">
			<input type="file" ref="fileInput" @change="handleFileChange" :disabled="uploading"
				style="display: block; margin-bottom: 15px; width: 100%" />

			<div v-if="selectedFile"
				style="display: flex; align-items: center; gap: 8px; margin: 10px 0; color: #606266">
				<el-icon :style="{ fontSize: '18px', color: 'var(--icon-color)' }">
					<Document />
				</el-icon>
				<span
					style="font-size:14px; max-width:300px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap">
					{{ selectedFile.name }}
				</span>
				<span style="font-size:12px; color:#909399">
					({{ formatFileSize(selectedFile.size) }})
				</span>
			</div>

			<el-progress :percentage="progress" :status="errorMessage ? 'exception' : undefined"
				style="margin:15px 0" />

			<div v-if="errorMessage" style="margin-top:10px">
				<el-alert :title="errorMessage" type="error" :closable="false" />
			</div>

			<div style="margin-top:20px; display:flex; justify-content:flex-end; gap:10px">
				<el-button type="primary" @click="startUpload" :disabled="!selectedFile || uploading"
					:loading="uploading">
					{{ uploading ? '上传中...' : '开始上传' }}
				</el-button>
				<el-button @click="showDialog = false" :disabled="uploading">
					取消
				</el-button>
			</div>
		</div>
	</el-dialog>
  `
}